package com.gwfd.mes.app.service;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.enums.IEnum;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gwfd.mes.app.domain.BaseDomain;
import com.gwfd.mes.app.core.def.mapper.MesMapper;
import com.gwfd.mes.app.o.DeleteBak;
import com.gwfd.mes.app.o.TableColumn;
import com.gwfd.mes.app.o.TableRow;
import online.bwbear.core.utils.id.MID;
import online.bwbear.core.utils.o.LoginUserTemplate;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.Field;
import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 张照威
 * @date 2020/8/3
 * @mail 865533614@qq.com
 * @describe
 */
public abstract class CoreService<M extends BaseMapper<T>, T extends BaseDomain> extends ServiceImpl<M, T> implements WorkIService<T> {

    @Autowired
    private MesMapper<T> mesMapper;

    /**
     * 逻辑删除
     * @param entityList
     */
    protected int deleteBatchLogicById(List<T> entityList) throws Exception {
        if (CollectionUtils.isEmpty(entityList)) {
            return 0;
        }
        LoginUserTemplate loginUser = getLoginUser();
        String tableName = getTableName(entityList.get(0).getClass());
        return mesMapper.deleteBatchLogicByEntityId(tableName, entityList, loginUser.getTenantId(), loginUser.getUserId());
    }

    /**
     * 逻辑删除
     * @param entity
     */
    protected int deleteLogicByEntityId(T entity) throws Exception {
        LoginUserTemplate loginUser = getLoginUser();
        String tableName = getTableName(entity.getClass());
        return mesMapper.deleteLogicByEntityId(tableName, entity, loginUser.getTenantId(), loginUser.getUserId());
    }


    /**
     * 逻辑删除
     * @param a
     * @param ids
     */
    protected int deleteBatchLogicById(Class a,List<String> ids) throws Exception {
        if (CollectionUtils.isEmpty(ids)) {
            return 0;
        }
        LoginUserTemplate loginUser = getLoginUser();
        String tableName = getTableName(a);
        return mesMapper.deleteBatchLogicById(tableName,ids,loginUser.getTenantId(),loginUser.getUserId());
    }


    /**
     * 逻辑删除
     * @param id
     */
    protected int deleteLogicByEntityId(Class a,String id) throws Exception {
        LoginUserTemplate loginUser = getLoginUser();
        String tableName = getTableName(a);
        return mesMapper.deleteLogicById(tableName,id,loginUser.getTenantId(),loginUser.getUserId());
    }


    /**
     * 新增
     * @param entity
     * @return
     */
    protected int insert(T entity) throws Exception {
        if(entity.getId()==null){
            entity.setId(createId());
        }
        LoginUserTemplate loginUser = getLoginUser();
        setInsetDef(entity,loginUser);
        return baseMapper.insert(entity);
    }

    /**
     * 批量新增
     * @param entityList
     * @return
     */
    protected boolean insertBatch(List<T> entityList) throws Exception {
        String tableName = getTableName(entityList.get(0).getClass());
        setInsertDefs(entityList);
        List<TableRow> tableRowList = new ArrayList<>();
        for (T entity : entityList) {
            if(entity.getId()==null){
                entity.setId(createId());
            }
            List<TableColumn> tableColumn = getSetTableColumn(entity, false,true);
            tableColumn.add(0,new TableColumn("id",entity.getId()));
            TableRow tableRow = new TableRow(entity.getId(),entity.getVersionNumber(),entity.getEnableState(),tableColumn);
            tableRowList.add(tableRow);
        }
        StringBuilder colName = new StringBuilder();
        List<TableColumn> tableColumnList = tableRowList.get(0).getTableColumnList();
        tableColumnList.stream().forEach(col->{
            colName.append(col.getTableColumnName()).append(',');
        });
        colName.deleteCharAt(colName.length()-1);
        StringBuilder colValue = new StringBuilder();
        tableRowList.stream().forEach(row->{
            List<TableColumn> tableColumnList1 = row.getTableColumnList();
            colValue.append('(');
            tableColumnList1.stream().forEach(col->{
                Object tableColumnValue = col.getTableColumnValue();
                if(tableColumnValue == null){
                    colValue.append("null");
                }else{
                    if(tableColumnValue instanceof Timestamp||tableColumnValue instanceof String||tableColumnValue instanceof IEnum){
                        colValue.append('\'').append(tableColumnValue).append('\'');
                    }else if(tableColumnValue instanceof Boolean){
                        if((Boolean)tableColumnValue){
                            colValue.append(1);
                        }else{
                            colValue.append(0);
                        }
                    }
                    else{
                        colValue.append(tableColumnValue);
                    }
                }
                colValue.append(',');
            });
            colValue.deleteCharAt(colValue.length()-1);
            colValue.append("),");
        });
        colValue.deleteCharAt(colValue.length()-1);
        mesMapper.insertBatch2(tableName,colName.toString(),colValue.toString());
        return true;
    }

    /**
     * 批量设置插入默认值
     * @param entityList
     */
    private void setInsertDefs(Collection<T> entityList){
        LoginUserTemplate loginUser = getLoginUser();
        entityList.stream().forEach(t->{
            setInsetDef(t,loginUser);
        });
    }

    /**
     * 设置插入
     * @param t
     * @param loginUser
     */
    private void setInsetDef(T t,LoginUserTemplate loginUser){
        if(t.getEnableState()==null){
            t.setEnableState(1);
        }
        t.setDeleteState(0);
        t.setCreateBy(loginUser.getUserId());
        t.setTenantId(loginUser.getTenantId());
        t.setCreateDate(new Timestamp(new Date().getTime()));
        t.setVersionNumber(1);
        setUpdateDef(t,loginUser);
    }

    /**
     * 设置修改默认值
     * @param t
     * @param loginUser
     */
    private void setUpdateDef(T t,LoginUserTemplate loginUser){
        t.setLastUpdateBy(loginUser.getUserId());
        t.setLastUpdateDate(new Timestamp(new Date().getTime()));
    }

    /**
     * 绝对修改
     * @param entity
     * @return
     */
    public int updateAbsolutelyById(T entity) throws Exception {
        return updateByEntityId(entity,false);
    }

    public int updateAbsolutelyBatchById(Collection<T> entityList) throws Exception {
        List<T> tList = new ArrayList<>(entityList);
        return updateBatchByEntityId(tList,false);
    }

    /**
     * 相对修改
     * @param entity
     * @return
     */
    public int updateRelativeById(T entity) throws Exception {
        return updateByEntityId(entity,true);
    }

    public int updateRelativeBatchById(Collection<T> entityList) throws Exception {
        List<T> tList = new ArrayList<>(entityList);
        return updateBatchByEntityId(tList,true);
    }

    private int updateBatchByEntityId(List<T> entityList,boolean relativeFlag) throws Exception {
        LoginUserTemplate loginUser = getLoginUser();
        String tableName = getTableName(entityList.get(0).getClass());
        List<TableRow> tableRowList = new ArrayList<>();
        for (T entity : entityList) {
            List<TableColumn> tableColumn = getSetTableColumn(entity, relativeFlag,false);
            TableRow tableRow = new TableRow(entity.getId(),entity.getVersionNumber(),entity.getEnableState(),tableColumn);
            tableRowList.add(tableRow);
        }
        return mesMapper.updateBatchByEntityId(tableName,tableRowList,loginUser.getTenantId(), loginUser.getUserId());
    }

    private int updateByEntityId(T entity,boolean relativeFlag) throws Exception {
        if(!relativeFlag&&entity.getVersionNumber()==null){
            throw new Exception("版本号异常");
        }
        LoginUserTemplate loginUser = getLoginUser();
        String tableName = getTableName(entity.getClass());
        setUpdateDef(entity,loginUser);
        List<TableColumn> tableColumnList = getSetTableColumn(entity,relativeFlag,false);
        return mesMapper.updateById(tableName, entity.getId() ,tableColumnList,entity.getVersionNumber(), loginUser.getTenantId(), loginUser.getUserId());
    }

    private List<TableColumn> getSetTableColumn(T entity, boolean relativeFlag , boolean isAll) throws Exception {
        List<TableColumn> tableColumnList = new ArrayList<>();
        Field[] declaredFields = entity.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            field.setAccessible(true);
            TableField annotation = field.getAnnotation(TableField.class);
            if(annotation.exist()){
                String tableColumnName = annotation.value();
                Object tableColumnValue = field.get(entity);
                if(relativeFlag&&tableColumnValue==null){
                    continue;
                }
                tableColumnList.add(new TableColumn(tableColumnName,tableColumnValue));
            }
        }
        if(isAll){
            tableColumnList.add(new TableColumn("tenant_id",entity.getTenantId()));
            tableColumnList.add(new TableColumn("enable_state",entity.getEnableState()));
            tableColumnList.add(new TableColumn("delete_state",entity.getDeleteState()));
            tableColumnList.add(new TableColumn("create_by",entity.getCreateBy()));
            tableColumnList.add(new TableColumn("create_date",entity.getCreateDate()));
            tableColumnList.add(new TableColumn("last_update_by",entity.getLastUpdateBy()));
            tableColumnList.add(new TableColumn("last_update_date",entity.getLastUpdateDate()));
            tableColumnList.add(new TableColumn("version_number",entity.getVersionNumber()));
        }else{
            if(entity.getEnableState()!=null){
                tableColumnList.add(new TableColumn("enable_state",entity.getEnableState()));
            }
        }
        return tableColumnList;
    }

    private String getTableName(Class tClass) throws Exception {
        TableName annotation = (TableName)tClass.getAnnotation(TableName.class);
        if (annotation==null) {
            throw new Exception("待操作对象不是实体类");
        }
        String tableName = annotation.value();
        return tableName;
    }

    private String createId(){
        return MID.generateShort();
    }


    protected List<DeleteBak> queryDeleteDataBak(String tenantCode , Class tClass) throws Exception {
        String tableName = getTableName(tClass);
        Timestamp collectDate = new Timestamp(System.currentTimeMillis());
        List<T> deleteData = queryDeleteData();
        List<DeleteBak> deleteBakList = new ArrayList<>();
        ObjectMapper mapper = new ObjectMapper();
        for (T data : deleteData) {
            String json = mapper.writeValueAsString(data);
            DeleteBak deleteBak = new DeleteBak(tenantCode,tableName,json,collectDate);
            deleteBakList.add(deleteBak);
        }
        return deleteBakList;
    }

    private List<T> queryDeleteData(){
        List<T> deleteData = baseMapper.selectList(new QueryWrapper<T>()
            .eq("delete_state",1)
        );
        return deleteData;
    }

    protected int clearDeleteDate(){
        int deleteCount = baseMapper.delete(new QueryWrapper<T>()
                .eq("delete_state",1)
        );
        return deleteCount;
    }

    public Map<String,T> queryMapByIds(List<String> ids){
        if(ids==null||ids.size()<1){
            return new HashMap<>();
        }
        List<T> ts = baseMapper.selectBatchIds(ids);
        if(ts==null||ts.size()<1){
            return new HashMap<>();
        }
        Map<String, T> map = ts.stream().collect(Collectors.toMap(T::getId, e -> e, (e1, e2) -> e2));
        return map;
    }

}
